/*
 *  +----------------------------------------------------------------------
 *  | sophon [ A FAST GAME FRAMEWORK ]
 *  +----------------------------------------------------------------------
 *  | Copyright (c) 2023-2029 All rights reserved.
 *  +----------------------------------------------------------------------
 *  | Licensed ( http:www.apache.org/licenses/LICENSE-2.0 )
 *  +----------------------------------------------------------------------
 *  | Author: jqiris <1920624985@qq.com>
 *  +----------------------------------------------------------------------
 */

use std::cmp::Eq;
use std::hash::Hash;

use dashmap::DashMap;

use super::*;

pub struct Finder<T> {
    servers: DashMap<String, DashMap<T, Server>>,
}

impl<T: Eq + Hash + Clone + Into<String>> Finder<T> {
    pub async fn new() -> Arc<Self> {
        let finder = Arc::new(Self {
            servers: DashMap::new(),
        });
        finder
    }

    pub fn get_server_cache(&self, server_type: &str, arg: T) -> Option<Server> {
        self.servers.get(server_type).and_then(|server_list| {
            server_list
                .get(&arg)
                .and_then(|server| Some(server.to_owned()))
        })
    }
    pub async fn get_server_discover(
        &self,
        server_type: &str,
        arg: T,
        options: Option<Vec<FilterOption>>,
    ) -> Option<Server> {
        let args = arg.clone().into();
        let server = get_server_by_type(server_type, &args, options).await;
        if let Some(s) = &server {
            let srt = server_type.into();
            let table = self.servers.entry(srt).or_default();
            table.insert(arg, s.clone());
        };
        server
    }
    pub async fn get_user_server(
        &self,
        server_type: &str,
        arg: T,
        options: Option<Vec<FilterOption>>,
    ) -> Option<Server> {
        if let Some(s) = self.get_server_cache(server_type, arg.clone()) {
            return Some(s);
        };
        if let Some(s) = self.get_server_discover(server_type, arg, options).await {
            return Some(s);
        };
        None
    }
    pub fn remove_user_server(&self, arg: T) {
        for server_list in &self.servers {
            server_list.remove(&arg);
        }
    }
}

impl<T: Eq + Hash> ServerEventHandler for Finder<T> {
    fn server_event_handle(&self, ev: &EventType, server: &Server) {
        match ev {
            _ => {
                self.servers.remove(&server.server_type);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_server_event() {
        let finder = Finder::<String>::new().await;
        let mut handlers = Vec::new();
        let hander: ServerHander = finder;
        handlers.push(hander);
        register_server_event_handlers(&mut handlers).await;
    }
}
